package com.example.backend.service;

import com.example.backend.domain.entity.Ticket;
import com.example.backend.domain.entity.User;
import com.example.backend.domain.enums.Role;
import com.example.backend.domain.enums.TicketPriority;
import com.example.backend.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 工单自动分配规则引擎
 * 基于分类、优先级、工作负载等因素自动分配工单
 */
@Service
public class TicketAutoAssignmentService {

    @Autowired
    private UserRepository userRepository;

    /**
     * 分配规则配置
     */
    public static class AssignmentRule {
        private Long categoryId;
        private String categoryCode;
        private TicketPriority priority;
        private List<String> requiredSkills;
        private Long preferredAssigneeId;
        private String ruleName;
        private int rulePriority; // 规则优先级
        private boolean enabled;

        // Getters and Setters
        public Long getCategoryId() { return categoryId; }
        public void setCategoryId(Long categoryId) { this.categoryId = categoryId; }
        public String getCategoryCode() { return categoryCode; }
        public void setCategoryCode(String categoryCode) { this.categoryCode = categoryCode; }
        public TicketPriority getPriority() { return priority; }
        public void setPriority(TicketPriority priority) { this.priority = priority; }
        public List<String> getRequiredSkills() { return requiredSkills; }
        public void setRequiredSkills(List<String> requiredSkills) { this.requiredSkills = requiredSkills; }
        public Long getPreferredAssigneeId() { return preferredAssigneeId; }
        public void setPreferredAssigneeId(Long preferredAssigneeId) { this.preferredAssigneeId = preferredAssigneeId; }
        public String getRuleName() { return ruleName; }
        public void setRuleName(String ruleName) { this.ruleName = ruleName; }
        public int getRulePriority() { return rulePriority; }
        public void setRulePriority(int rulePriority) { this.rulePriority = rulePriority; }
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
    }

    /**
     * 分配结果
     */
    public static class AssignmentResult {
        private User assignedUser;
        private String assignmentReason;
        private double confidenceScore;
        private List<String> appliedRules;
        private boolean autoAssigned;

        public AssignmentResult() {
            this.appliedRules = new ArrayList<>();
            this.autoAssigned = false;
        }

        // Getters and Setters
        public User getAssignedUser() { return assignedUser; }
        public void setAssignedUser(User assignedUser) { this.assignedUser = assignedUser; }
        public String getAssignmentReason() { return assignmentReason; }
        public void setAssignmentReason(String assignmentReason) { this.assignmentReason = assignmentReason; }
        public double getConfidenceScore() { return confidenceScore; }
        public void setConfidenceScore(double confidenceScore) { this.confidenceScore = confidenceScore; }
        public List<String> getAppliedRules() { return appliedRules; }
        public void setAppliedRules(List<String> appliedRules) { this.appliedRules = appliedRules; }
        public boolean isAutoAssigned() { return autoAssigned; }
        public void setAutoAssigned(boolean autoAssigned) { this.autoAssigned = autoAssigned; }
    }

    /**
     * 预定义的分配规则
     */
    private final List<AssignmentRule> defaultRules = Arrays.asList(
        createRule("紧急工单规则", null, TicketPriority.URGENT, Arrays.asList("紧急处理"), null, 100),
        createRule("技术问题规则", "TECH", null, Arrays.asList("技术"), null, 90),
        createRule("账户问题规则", "ACCOUNT", null, Arrays.asList("账户管理"), null, 80),
        createRule("功能咨询规则", "FEATURE", null, Arrays.asList("产品知识"), null, 70)
    );

    /**
     * 创建分配规则
     */
    private AssignmentRule createRule(String ruleName, String categoryCode, TicketPriority priority, 
                                     List<String> skills, Long preferredAssignee, int priorityValue) {
        AssignmentRule rule = new AssignmentRule();
        rule.setRuleName(ruleName);
        rule.setCategoryCode(categoryCode);
        rule.setPriority(priority);
        rule.setRequiredSkills(skills);
        rule.setPreferredAssigneeId(preferredAssignee);
        rule.setRulePriority(priorityValue);
        rule.setEnabled(true);
        return rule;
    }

    /**
     * 自动分配工单
     * 
     * @param ticket 工单
     * @return 分配结果
     */
    public AssignmentResult autoAssignTicket(Ticket ticket) {
        AssignmentResult result = new AssignmentResult();

        // 获取可分配的客服人员
        List<User> availableAgents = getAvailableAgents();

        if (availableAgents.isEmpty()) {
            result.setAssignmentReason("没有可用的客服人员");
            return result;
        }

        // 应用分配规则
        User assignedUser = applyAssignmentRules(ticket, availableAgents, result);

        if (assignedUser != null) {
            result.setAssignedUser(assignedUser);
            result.setAutoAssigned(true);
            result.setConfidenceScore(calculateConfidenceScore(ticket, assignedUser));
        } else {
            // 使用负载均衡分配
            assignedUser = assignByLoadBalancing(availableAgents);
            result.setAssignedUser(assignedUser);
            result.setAssignmentReason("基于负载均衡分配");
            result.setAutoAssigned(true);
            result.setConfidenceScore(0.5); // 负载均衡的置信度较低
        }

        return result;
    }

    /**
     * 获取可分配的客服人员
     * 
     * @return 客服人员列表
     */
    private List<User> getAvailableAgents() {
        return userRepository.findByRoleAndStatus(Role.AGENT, com.example.backend.domain.enums.UserStatus.ACTIVE, 
                org.springframework.data.domain.Pageable.unpaged())
                .stream()
                .filter(user -> user.getStatus() == com.example.backend.domain.enums.UserStatus.ACTIVE)
                .collect(Collectors.toList());
    }

    /**
     * 应用分配规则
     * 
     * @param ticket 工单
     * @param availableAgents 可用客服
     * @param result 分配结果
     * @return 分配的用户
     */
    private User applyAssignmentRules(Ticket ticket, List<User> availableAgents, AssignmentResult result) {
        // 按规则优先级排序
        List<AssignmentRule> sortedRules = defaultRules.stream()
                .filter(AssignmentRule::isEnabled)
                .sorted(Comparator.comparing(AssignmentRule::getRulePriority).reversed())
                .collect(Collectors.toList());

        for (AssignmentRule rule : sortedRules) {
            if (matchesRule(ticket, rule)) {
                User assignedUser = findUserByRule(ticket, rule, availableAgents);
                if (assignedUser != null) {
                    result.getAppliedRules().add(rule.getRuleName());
                    result.setAssignmentReason("应用规则: " + rule.getRuleName());
                    return assignedUser;
                }
            }
        }

        return null;
    }

    /**
     * 检查工单是否匹配规则
     * 
     * @param ticket 工单
     * @param rule 规则
     * @return 是否匹配
     */
    private boolean matchesRule(Ticket ticket, AssignmentRule rule) {
        // 检查分类匹配
        if (rule.getCategoryCode() != null && ticket.getCategory() != null) {
            if (!rule.getCategoryCode().equals(ticket.getCategory().getCategoryCode())) {
                return false;
            }
        }

        // 检查优先级匹配
        if (rule.getPriority() != null) {
            if (!rule.getPriority().equals(ticket.getPriority())) {
                return false;
            }
        }

        return true;
    }

    /**
     * 根据规则查找用户
     * 
     * @param ticket 工单
     * @param rule 规则
     * @param availableAgents 可用客服
     * @return 分配的用户
     */
    private User findUserByRule(Ticket ticket, AssignmentRule rule, List<User> availableAgents) {
        // 优先分配指定的用户
        if (rule.getPreferredAssigneeId() != null) {
            Optional<User> preferredUser = availableAgents.stream()
                    .filter(user -> user.getId().equals(rule.getPreferredAssigneeId()))
                    .findFirst();
            if (preferredUser.isPresent()) {
                return preferredUser.get();
            }
        }

        // 根据技能匹配
        if (rule.getRequiredSkills() != null && !rule.getRequiredSkills().isEmpty()) {
            return findUserBySkills(rule.getRequiredSkills(), availableAgents);
        }

        // 根据工作负载选择
        return selectByWorkload(availableAgents);
    }

    /**
     * 根据技能查找用户
     * 
     * @param requiredSkills 所需技能
     * @param availableAgents 可用客服
     * @return 匹配的用户
     */
    private User findUserBySkills(List<String> requiredSkills, List<User> availableAgents) {
        // 这里可以根据用户的技能标签进行匹配
        // 暂时返回工作负载最少的用户
        return selectByWorkload(availableAgents);
    }

    /**
     * 基于负载均衡选择用户
     * 
     * @param availableAgents 可用客服
     * @return 选择的用户
     */
    private User selectByWorkload(List<User> availableAgents) {
        if (availableAgents.isEmpty()) {
            return null;
        }

        // 计算每个用户的工作负载（这里简化处理）
        Map<User, Integer> workloadMap = new HashMap<>();
        for (User agent : availableAgents) {
            // 这里应该查询用户当前处理的工单数量
            // 暂时使用随机数模拟
            workloadMap.put(agent, new Random().nextInt(10));
        }

        // 选择工作负载最少的用户
        return workloadMap.entrySet().stream()
                .min(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(availableAgents.get(0));
    }

    /**
     * 计算分配置信度
     * 
     * @param ticket 工单
     * @param assignedUser 分配的用户
     * @return 置信度分数
     */
    private double calculateConfidenceScore(Ticket ticket, User assignedUser) {
        double score = 0.5; // 基础分数

        // 根据优先级调整分数
        switch (ticket.getPriority()) {
            case URGENT:
                score += 0.3;
                break;
            case HIGH:
                score += 0.2;
                break;
            case MEDIUM:
                score += 0.1;
                break;
            case LOW:
                score += 0.0;
                break;
        }

        // 根据分类匹配调整分数
        if (ticket.getCategory() != null) {
            score += 0.2;
        }

        return Math.min(score, 1.0);
    }

    /**
     * 检查是否可以自动分配
     * 
     * @param ticket 工单
     * @return 是否可以自动分配
     */
    public boolean canAutoAssign(Ticket ticket) {
        // 检查是否有可用的客服
        List<User> availableAgents = getAvailableAgents();
        if (availableAgents.isEmpty()) {
            return false;
        }

        // 检查工单状态
        if (ticket.getStatus() != com.example.backend.domain.enums.TicketStatus.OPEN) {
            return false;
        }

        // 检查是否已经分配
        if (ticket.getAssignedTo() != null) {
            return false;
        }

        return true;
    }

    /**
     * 获取分配建议
     * 
     * @param ticket 工单
     * @return 分配建议列表
     */
    public List<AssignmentResult> getAssignmentSuggestions(Ticket ticket) {
        List<AssignmentResult> suggestions = new ArrayList<>();
        List<User> availableAgents = getAvailableAgents();

        for (User agent : availableAgents) {
            AssignmentResult suggestion = new AssignmentResult();
            suggestion.setAssignedUser(agent);
            suggestion.setConfidenceScore(calculateConfidenceScore(ticket, agent));
            suggestion.setAssignmentReason("基于工作负载和技能匹配");
            suggestions.add(suggestion);
        }

        // 按置信度排序
        suggestions.sort(Comparator.comparing(AssignmentResult::getConfidenceScore).reversed());

        return suggestions.stream().limit(3).collect(Collectors.toList());
    }

    /**
     * 重新分配工单
     * 
     * @param ticket 工单
     * @param reason 重新分配原因
     * @return 分配结果
     */
    public AssignmentResult reassignTicket(Ticket ticket, String reason) {
        AssignmentResult result = autoAssignTicket(ticket);
        result.setAssignmentReason("重新分配: " + reason);
        return result;
    }

    /**
     * 获取分配规则列表
     * 
     * @return 分配规则列表
     */
    public List<AssignmentRule> getAssignmentRules() {
        return new ArrayList<>(defaultRules);
    }

    /**
     * 添加自定义分配规则
     * 
     * @param rule 分配规则
     */
    public void addAssignmentRule(AssignmentRule rule) {
        defaultRules.add(rule);
        // 按优先级重新排序
        defaultRules.sort(Comparator.comparing(AssignmentRule::getRulePriority).reversed());
    }

    /**
     * 更新分配规则
     * 
     * @param ruleName 规则名称
     * @param enabled 是否启用
     */
    public void updateAssignmentRule(String ruleName, boolean enabled) {
        defaultRules.stream()
                .filter(rule -> rule.getRuleName().equals(ruleName))
                .findFirst()
                .ifPresent(rule -> rule.setEnabled(enabled));
    }

    /**
     * 基于负载均衡分配工单
     * 
     * @param availableAgents 可用客服列表
     * @return 分配的用户
     */
    private User assignByLoadBalancing(List<User> availableAgents) {
        if (availableAgents.isEmpty()) {
            return null;
        }
        
        // 简单的轮询分配策略
        // 在实际应用中，这里可以根据工单数量、响应时间等因素进行更复杂的负载均衡
        return availableAgents.get(0);
    }
}
